#include "Sphere.h"


Sphere::Sphere(vec4 _pos, vec3 _rot, float _rad):Shape(_pos, _rot){
	rad = _rad;
}


Sphere::~Sphere(){
}


bool Sphere::intersect(Intersection &_int){
	Stats::instance()->primTest();	//increment the intersection test count
	//printf("Ok, let's find a sphere intersection\n");
	//http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection

	Ray _theRay = *(_int.ray());

	//ray-sphere intersection test
	vec3 rayOrig = _theRay.origin();
	vec3 rayDir = _theRay.direction();
	
	//transform the ray into object space
	//do a proper transformation with rotation and scaling
	rayOrig -= pos.xyz();
	
	//compute coefficients for the quadratic equation
	float a = dot(rayDir, rayDir);
	float b = 2.0f * dot(rayDir, rayOrig);
	float c = dot(rayOrig, rayOrig) - (rad * rad);
	
	//discriminant
	float disc = b * b - 4.0f * a * c;
	
	//if there are no real roots
	if(disc < 0.0f){
		return false;
	}
	
	//compute q
	float discSqrt = glm::sqrt(disc);
	float q;
	if(b < 0){
		q = -0.5f * (b - discSqrt);
	}
	else{
		q = -0.5f * (b + discSqrt);
	}
	
	//compute intersection distances
	float t0 = q / a;
	float t1;
	if (q != 0.0f){
		t1 = c / q;
	}
	else{
		t1 = 1e30f;
	}
	
	
	//get the closer point
	if(t1 < t0){
		float temp = t0;
		t0 = t1;
		t1 = temp;
	}
	
	float _dist;
	if (t0 >= _theRay.maxDist() || t1 < _theRay.minDist()){
		return false;
	}
	if (t0 >= _theRay.minDist()){
		//something
		_dist = t0;
	}
	else if (t1 < _theRay.maxDist()){
		_dist = t1;
	}
	else{
		return false;
	}
	if (_dist < _int.dist()){
		//set the new closest distance
		_int.dist(_dist);
		//set the new closest shape
		_int.shape(this);
		//set the surface normal at the intersection point
		vec3 _pt = _theRay.pointAtDepth(_dist);
		vec3 _norm = normalize(_pt - pos.xyz());
		_int.surfNorm(_norm);
	}
	
	_int.intersected(true);
	Stats::instance()->primInt();	//increment the intersection count
	return true;
}

vec4 Sphere::getColor(Intersection &_int){
	//calculate the surface color based on the Sphere's ShaderCollection
	//printf("This is a sphere color\n");
	if (shade == NULL){
		return vec4(0.7, 0, 0, 0);
	}
	return shade->getColor(_int);
	
}

vec3 Sphere::getMaxBound(){
	float maxX = pos.x + rad;
	float maxY = pos.y + rad;
	float maxZ = pos.z + rad;
	return vec3(maxX, maxY, maxZ);
}
vec3 Sphere::getMinBound(){
	float minX = pos.x - rad;
	float minY = pos.y - rad;
	float minZ = pos.z - rad;
	return vec3(minX, minY, minZ);
}

vec3 Sphere::getCenter(){
	return pos.xyz;
}
